#ifndef __ATOMICQUEUE_H__
#define __ATOMICQUEUE_H__

#include <memory>
#include <queue>
#include "HFuncType.h"
#include "QueueObject.h"
#include "ThreadSafePrinter.h"

HTHREADPOOL_NAMESPACE_BEGIN

    template<typename T>
    class AtomicQueue : public QueueObject
    {
    public:
        AtomicQueue() = default;
        // 已经继承，可选择
        THREADPOOL_NO_ALLOWED_COPY(AtomicQueue)

        void waitPop(T& value)
        {
            std::lock_guard<std::mutex> lock(m_mutex);
            m_cv.wait(lock, [this] { return !m_queue.empty(); });
            value = std::move(*m_queue.front());
            m_queue.pop();
        }

        bool tryPop(T& value)
        {
            std::lock_guard<std::mutex> lock(m_mutex);
            if(m_queue.empty()) {
                return false;
            }
            ThreadSafePrinter::print("m_queue size:%d", m_queue.size());
            value = std::move(*m_queue.front());
            m_queue.pop();
            return true;
        }

        bool tryPop(std::vector<T>& values, int maxPoolBatchSize)
        {
            std::lock_guard<std::mutex> lock(m_mutex);
            if(m_queue.empty() || maxPoolBatchSize <= 0) {
                return false;
            }

            while(!m_queue.empty() && maxPoolBatchSize--) {
                values.emplace_back(std::move(*m_queue.front()));
                m_queue.pop();
            }

            return true;
        }

        std::unique_ptr<T> waitPop()
        {
            std::lock_guard<std::mutex> lock(m_mutex);
            m_cv.wait(lock, [this] { return !m_queue.empty(); });
            auto result = std::move(m_queue.front());
            m_queue.pop();

            return result;
        }

        std::unique_ptr<T> tryPop()
        {
            std::lock_guard<std::mutex> lock(m_mutex);
            if(m_queue.empty()) {
                return std::unique_ptr<T>();
            }

            auto result = std::move(m_queue.front());
            m_queue.pop();

            return result;
        }

        void push(T&& value)
        {
            std::unique_ptr<T>          task(std::make_unique<T>(std::move(value)));
            std::lock_guard<std::mutex> lock(m_mutex);
            m_queue.emplace(std::move(task));
            m_cv.notify_one();
        }

        bool empty() const
        {
            std::lock_guard<std::mutex> lock(m_mutex);
            return m_queue.empty();
        }

    private:
        std::queue<std::unique_ptr<T>> m_queue;
    };

HTHREADPOOL_NAMESPACE_END

#endif
